package com.buddy.learn.spring.framework.aop.intercept;

import com.buddy.learn.spring.framework.aop.aspect.BJoinPoint;

import java.lang.reflect.Method;
import java.util.List;

//具体i执行拦截器的过程
public class BMethodInvocation implements BJoinPoint{

    private Object proxy;
    private Object target;
    private Method method;
    private Object[] arguments;
    private Class<?> targetClass;
    private List<Object> interceptorsAndDynamicMethodMatchers;

    //Spring中定义一个索引，从-1开始记录当前拦截器执行的位置
    private int currentInterceptorIndex = -1;


    public BMethodInvocation(Object proxy, Object target, Method method,
                             Object[] arguments, Class<?> targetClass,
                             List<Object> interceptorsAndDynamicMethodMatchers) {
        this.proxy = proxy;
        this.target = target;
        this.method = method;
        this.arguments = arguments;
        this.targetClass = targetClass;
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }

    //解析配置文件 执行拦截器链里的每一个方法，每一个拦截器链中的每一个元素都是实现intercepter拦截器
    public Object proceed() throws Throwable {
        //拦截器链的调用过程

        //	We start with an index of -1 and increment early.
        //如果Interceptor执行完了，则执行joinPoint
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.method.invoke(this.target, this.arguments);
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        //如果要动态匹配joinPoint
        if (interceptorOrInterceptionAdvice instanceof BMethodInterceptor) {
            BMethodInterceptor mi =
                    (BMethodInterceptor) interceptorOrInterceptionAdvice;
            //动态匹配：运行时参数是否满足匹配条件
            return mi.invoke(this);
        } else {
            //动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor
            return proceed();
        }
    }

    @Override
    public Object getThis() {
        return this.target;
    }

    @Override
    public Object[] getArguments() {
        return this.getArguments();
    }

    @Override
    public Method getMethod() {
        return this.getMethod();
    }

    @Override
    public void setUserAttribute(String key, Object val) {

    }

    @Override
    public Object getUserAttribute(String key) {
        return null;
    }
}
